package com.ahcloud.enhance.lock.base;

import com.google.common.base.Throwables;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;

/**
 * @program: distributedlock-enhance
 * @description:
 * @author: YuKai Fan
 * @create: 2024/4/30 23:14
 **/
@Slf4j
public class LockUtils {

    private static ILock lock;

    public static <T> void setLocker(ILock<T> lock) {
        LockUtils.lock = lock;
    }

    public static <T> T getLockClient() {
        return (T) LockUtils.lock.getClient();
    }

    /**
     * 一直等待，直到获取锁
     * @param lockKey
     */
    public static void lock(String lockKey) {
        try {
            log.info("{} lock, wait getLock", getLockName());
            lock.lock(lockKey);
        } catch (Exception e) {
            printGetLockLog(lockKey, false, e);
        }
    }

    /**
     * 没有返回值，获取锁，超时返回
     * @param lockKey
     * @param waitTime
     * @param unit
     */
    public static void lock(String lockKey, long waitTime, TimeUnit unit) {
        try {
            log.info("{} lock, wait getLock, waitTime is [{}], unit is [{}]", getLockName(), waitTime, unit);
            lock.lock(lockKey, waitTime, unit);
        } catch (Exception e) {
            printGetLockLog(lockKey, false, e);
        }
    }

    /**
     * 没有返回值，获取锁，超时返回
     * @param lockKey
     * @param waitTime
     */
    public static void lock(String lockKey, long waitTime) {
        lock(lockKey, waitTime, TimeUnit.SECONDS);
    }

    /**
     * 尝试获取分布式锁
     * @param lockKey
     * @return
     */
    public static boolean tryLock(String lockKey) {
        try {
            boolean result = lock.tryLock(lockKey);
            printGetLockLog(lockKey, result, null);
            return result;
        } catch (Exception e) {
            printGetLockLog(lockKey, false, e);
            return false;
        }
    }

    /**
     * 尝试获取分布式锁
     * @param lockKey
     * @param waitTime
     * @param unit
     * @return
     */
    public static boolean tryLock(String lockKey, long waitTime, TimeUnit unit) {
        try {
            boolean result = lock.tryLock(lockKey, waitTime, unit);
            printGetLockLog(lockKey, result, null);
            return result;
        } catch (Exception e) {
            printGetLockLog(lockKey, false, e);
            return false;
        }
    }

    /**
     * 尝试获取分布式锁
     * @param lockKey
     * @param waitTime
     * @return
     */
    public static boolean tryLock(String lockKey, long waitTime) {
        return tryLock(lockKey, waitTime, TimeUnit.SECONDS);
    }

    /**
     * 释放分布式锁
     * @param lockKey
     * @return
     */
    public static boolean unlock(String lockKey) {
        try {
            lock.unlock(lockKey);
            log.info("{} unlock, lockKey is [{}", getLockName(), lockKey);
            return true;
        } catch (Exception e) {
            log.error("{} unlock exception, lockKey is [{}], reason is {}", getLockName(), lockKey, Throwables.getStackTraceAsString(e));
            return false;
        }
    }

    private static void printGetLockLog(String lockKey, boolean result, Exception e) {
        if (e == null) {
            log.info("{} tryLock lockKey is [{}], result is [{}]", getLockName(), lockKey, result);
        } else {
            log.error("{} tryLock lockKey is [{}], get lock exception, reason is {}", getLockName(), lockKey, Throwables.getStackTraceAsString(e));
        }
    }

    private static String getLockName() {
        return LockUtils.lock.getClass().getSimpleName();
    }
}
